package globalVisionEntertainment.nba;

import gqqnbig.SystemHelper;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Callable;

import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class Program
{

	private static SimpleDateFormat onCourtTimeFormat;

	static
	{

		// dateFormat.setTimeZone(new SimpleTimeZone(0, "UTC"));
		TimeZone.setDefault(new SimpleTimeZone(0, "UTC"));
		onCourtTimeFormat = new SimpleDateFormat("H:m:ss");
	}

	public static void main(String[] args) throws Exception
	{

		String gameId;
		gameId = args[0];
		// gameId = "400490087";

		try
		{
			run(gameId);
		}
		catch (Exception e)
		{
			System.err.println("Error in loading game " + gameId);
			System.err.println("Error Message: " + e.getMessage());
			e.printStackTrace();
		}
	}

	private static void run(String gameId) throws ClassNotFoundException, Exception
	{

		System.out.println("Importing " + gameId);

		EspnGameRecord gameRecord = new EspnGameRecord(gameId);

		Class.forName("com.mysql.jdbc.Driver");
		Connection conn;
		try
		{
			conn = Database.getConnection();
			conn.setAutoCommit(true);

			// conn.setAutoCommit(true);

			if (BasketballRules.normalSectionCount != 4)
				throw new UnsupportedOperationException("The database scheme assumes 4 sections in a game.");

			Game game = gameRecord.getGameInfo();
			SimpleDateFormat mySqlDateFormat = new SimpleDateFormat("yyyy-MM-dd");
			mySqlDateFormat.setTimeZone(new SimpleTimeZone(0, "UTC"));

			insertGameToDatabase(gameId, conn, game, mySqlDateFormat);

			try
			{
				storeGameStatistic(conn, gameRecord, GameParty.Home);
				storeGameStatistic(conn, gameRecord, GameParty.Visitor);
			}
			catch (SQLException e)
			{
				if (e.getErrorCode() == 1062)
					System.err.println("Cannot import duplicate statistic. Have you imported game " + gameId + " ?");

				System.err.print("SQL Error: ");
				System.err.println(e.getMessage());
			}
			catch (Exception e)
			{
				e.printStackTrace();
				// TODO: handle exception
			}
			finally
			{
				conn.close();
			}
		}
		catch (SQLException e)
		{
			System.err.println("Failed to connect to mysql database. Is the service running?");
			System.err.println(e.toString());
		}
	}

	private static void insertGameToDatabase(String gameId, Connection conn, Game game, SimpleDateFormat mySqlDateFormat)
			throws SQLException
	{
		try
		{
			// @formatter:off
			String sql = String.format("insert into Game \n" + "values(\"%s\", \"%s\", \"%s\", \"%s\")", gameId,
					game.homeTeam, game.visitingTeam, mySqlDateFormat.format(game.date));
			// @formatter:on

			Statement statement = conn.createStatement();
			statement.execute(sql);
		}
		catch (SQLException e)
		{
			if (e.getErrorCode() == 1062)
			{
				System.out.println("Game metadata " + gameId + " already exists. Cannot import duplicate data.\n"
						+ "Continue to import player statistic.");

				System.out.print("SQL Error: ");
				System.out.println(e.getMessage());
			}
			else
				throw e;

		}
	}

	private static void storeGameStatistic(Connection conn, EspnGameRecord gameRecord, GameParty gameParty) throws Exception
	{
		PlayerGameStatistic[] playerGameStatisticsList = gameRecord.readGameStatistic(gameParty);

		for (PlayerGameStatistic pgs : playerGameStatisticsList)
		{
			String playerName = pgs.getPlayerName();
			PlayerQuarterStatistic[] list = pgs.getPlayerGameStatistic();

			PlayerQuarterStatistic absentStat = new PlayerQuarterStatistic(playerName, new Date(0), 0, 0);
			PlayerQuarterStatistic q1 = list[0];
			if (q1 == null)
				q1 = absentStat;

			PlayerQuarterStatistic q2 = list[1];
			if (q2 == null)
				q2 = absentStat;

			PlayerQuarterStatistic q3 = list[2];
			if (q3 == null)
				q3 = absentStat;

			PlayerQuarterStatistic q4 = list[3];
			if (q4 == null)
				q4 = absentStat;

			String onCourt1 = onCourtTimeFormat.format(q1.getOnCourtTime());
			String onCourt2 = onCourtTimeFormat.format(q2.getOnCourtTime());
			String onCourt3 = onCourtTimeFormat.format(q3.getOnCourtTime());
			String onCourt4 = onCourtTimeFormat.format(q4.getOnCourtTime());

			//http://espn.go.com/nba/playbyplay?gameId=320508013&period=4
			//Darius Morris上场不足1秒。
			if (onCourt1.equals("0:0:00") && onCourt2.equals("0:0:00") && onCourt3.equals("0:0:00") && onCourt4.equals("0:0:00"))
				continue;

			int plus1 = q1.getPlus();
			int plus2 = q2.getPlus();
			int plus3 = q3.getPlus();
			int plus4 = q4.getPlus();

			int minus1 = q1.getMinus();
			int minus2 = q2.getMinus();
			int minus3 = q3.getMinus();
			int minus4 = q4.getMinus();

			if (conn == null)
				return;

			Game game = gameRecord.getGameInfo();

			assert pgs.getPlayerName() != null;

			// @formatter:off
			String sql = String.format("insert into "
					+ "nba.PlayerStatistic(`PlayerName`, `Owner`, 													`Game`, 				`IsStarter`, 	`Position`, 	`Match Order`,				`OnCourt1`, `OnCourt2`, `OnCourt3`, `OnCourt4`, `Plus1`, `Plus2`, `Plus3`, `Plus4`, `Minus1`, `Minus2`, `Minus3`, `Minus4`)\n"
					             + "values(  \"%s\",     \"%s\",													 \"%s\", 				%s,          	\"%s\",     	 %s,						\"%s\",		\"%s\",		\"%s\",		\"%s\",  	%s,			%s,		%s,		%s,  	%s,			%s,		%s,			%s)", 
					             			playerName, gameParty==GameParty.Home?game.homeTeam:game.visitingTeam, gameRecord.getGameId(),pgs.isStarter(), pgs.getPosition(), pgs.getVirtualPosition(),  onCourt1, onCourt2, onCourt3, 		onCourt4, plus1, 	plus2, 		plus3, plus4, minus1,		minus2, minus3, minus4);
			// @formatter:on
			Statement statement = conn.createStatement();
			statement.execute(sql);

			// 读取head2head

			File scriptFile = new File(SystemHelper.getAppPath(Program.class), "head2headStatsReader.jar");
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", scriptFile.getAbsolutePath(), playerName,
					dateFormat.format(gameRecord.getGameInfo().date));
			// else
			// processBuilder = new ProcessBuilder(scriptFile.getAbsolutePath(), gameId);

			Process p = processBuilder.start();

			new Thread(new gqqnbig.StreamReaderThread(p.getInputStream(), System.out)).start();

			new Thread(new gqqnbig.StreamReaderThread(p.getErrorStream(), System.out)).start();

			p.waitFor();
		}
	}

	static int isEnoughPlayersOnCourt(ArrayList<PlayerInQuarterStatistic> playerStatistics)
	{
		int count = 0;
		for (PlayerInQuarterStatistic ps : playerStatistics)
		{
			if (ps.getEndTime().getTime() == 0)
				count++;
		}
		return count;

	}

	static List<PlayerQuarterStatistic> coalesceByName(List<PlayerInQuarterStatistic> playerStatistics)
	{
		// create a new copy, do not modify the argument.
		LinkedList<PlayerInQuarterStatistic> list = new LinkedList<PlayerInQuarterStatistic>(playerStatistics);

		ArrayList<PlayerQuarterStatistic> quarterStatistics = new ArrayList<PlayerQuarterStatistic>();

		for (int i = 0; i < list.size(); i++)
		{
			PlayerInQuarterStatistic p = list.get(i);
			String name = p.getPlayerName();

			long time = p.getOnCourtTime().getTime();
			int plus = p.getPlus();
			int minus = p.getMinus();

			for (int j = i + 1; j < list.size(); j++)
			{
				PlayerInQuarterStatistic p2 = list.get(j);
				if (p2.getPlayerName().equals(name))
				{
					time += p2.getOnCourtTime().getTime();
					plus += p2.getPlus();
					minus += p2.getMinus();

					list.remove(j);
					j--;
				}
			}

			PlayerQuarterStatistic pq = new PlayerQuarterStatistic(name, new Date(time), plus, minus);
			quarterStatistics.add(pq);
		}

		return quarterStatistics;

	}

	static ArrayList<String> getStarters(Element teamBlock)
	{
		Elements nameElements = teamBlock.select("tr:lt(5)>td:eq(0) a");

		ArrayList<String> starter = new ArrayList<String>(5);
		for (Element element : nameElements)
		{
			starter.add(element.text());
		}

		assert starter.size() <= 5;

		return starter;
	}

	static PlayerInQuarterStatistic getOnCourtPlayers(String playerName, List<PlayerInQuarterStatistic> playerStatistics)
	{
		for (PlayerInQuarterStatistic player : playerStatistics)
		{
			if (player.getEndTime() == null && player.getPlayerName().equals(playerName))
				return player;
		}

		// cannot find that player. Heuristically add the player to
		// playerStatistics.
		PlayerInQuarterStatistic ps = new PlayerInQuarterStatistic(playerName, new Date(BasketballRules.sectionLength * 60 * 1000));

		playerStatistics.add(ps);
		return ps;

	}

}
